package com.econ.powercloud.ems.service.biz;

import com.econ.powercloud.common.base.facade.enums.StatusType;
import com.econ.powercloud.common.base.facade.exception.CommonRuntimeException;
import com.econ.powercloud.common.base.facade.util.JacksonUtil;
import com.econ.powercloud.ems.common.enums.DeviceType;
import com.econ.powercloud.ems.common.enums.MeasureType;
import com.econ.powercloud.ems.common.enums.TagType;
import com.econ.powercloud.ems.common.enums.VirtualType;
import com.econ.powercloud.ems.constant.SysConstant;
import com.econ.powercloud.ems.dal.entity.*;
import com.econ.powercloud.ems.pojo.*;
import com.econ.powercloud.ems.pojo.scene.OpenApiHisDataVO;
import com.econ.powercloud.ems.service.common.QueryFlashDataCommonService;
import com.econ.powercloud.ems.service.common.QueryHisDataCommonService;
import com.econ.powercloud.ems.service.dao.*;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author : zjf
 * @Description : 获取单体相关的数据service
 * @Date : 2023/7/6 20:34
 * @Modified by : zjf
 */
@Service
public class UnitBodyDataService {
    @Autowired
    private EmsClusterDetailConfigDAO emsClusterDetailConfigDAO;
    @Autowired
    private EmsClusterConfigDAO emsClusterConfigDAO;
    @Autowired
    private ExtIotViceProductYcDAO extIotViceProductYcDAO;
    @Autowired
    private QueryHisDataCommonService queryHisDataCommonService;
    @Autowired
    private EmsDeviceDAO emsDeviceDAO;
    @Autowired
    private IotProductYcDAO iotProductYcDAO;
    @Autowired
    private QueryFlashDataCommonService queryFlashDataCommonService;

    /**
     * 获取蔟下所有电压集合图形
     * @param time
     * @param deviceCode
     * @return
     */
    public BatteryVoltageVO getBatteryVoltageCurve(Long time, String deviceCode) {
        Map<String, List<EchartsVO>> result = new LinkedHashMap<>();
        EmsDevice emsDevice = this.getBmuMonomerDeviceByClusterDeviceCode(deviceCode);
        //获取当前簇的电池pack分部情况
        EmsClusterConfig emsClusterConfig = emsClusterConfigDAO.getByDeviceCode(deviceCode);
        if(emsClusterConfig == null){
            return BatteryVoltageVO.builder().build();
        }
        List<EmsClusterDetailConfig> detailConfigList = emsClusterDetailConfigDAO.getListByType(emsClusterConfig.getType());
        if(CollectionUtils.isEmpty(detailConfigList)){
            return BatteryVoltageVO.builder().build();
        }
        Map<Integer, EmsClusterDetailConfig> detailConfigMap = detailConfigList.stream().collect(Collectors.toMap(EmsClusterDetailConfig::getPack, d -> d, (p1, p2) -> p1));
        Integer batteriesTotalNum = 0;
        for (EmsClusterDetailConfig config : detailConfigList){
            batteriesTotalNum = batteriesTotalNum + config.getBatteriesNum();
        }
        //获取簇下的单体电压点号,并截取部分数据
        List<ExtIotViceProductYc> ycSyncList = extIotViceProductYcDAO.getBaseMapper().selectByCondition(emsDevice.getProductKey(), emsDevice.getModuleCode(),
                TagType.DTU.getCode());
        if(batteriesTotalNum > ycSyncList.size()){
            throw new CommonRuntimeException(StatusType.FAIL,"该簇对应的电池簇模型的电压个数配置有误!");
        }
        ycSyncList = ycSyncList.subList(0, batteriesTotalNum);
        //拼接查询点号VO类
        List<EmsHisDataVO> hisDataVOList = Lists.newArrayList();
        //用来指向当前pack的电芯数的最后一个大小
        Integer packBatIndex = 0;
        for (int i = 1; i <= detailConfigMap.size(); i++) {
            EmsClusterDetailConfig emsClusterDetailConfig = detailConfigMap.get(i);
            List<ExtIotViceProductYc> ycSyncs = ycSyncList.subList(packBatIndex, packBatIndex + emsClusterDetailConfig.getBatteriesNum());
            for (int j = 1; j <= ycSyncs.size(); j++) {
                hisDataVOList.add(EmsHisDataVO.builder()
                        .pid(emsDevice.getInitDeviceCode() + SysConstant.SPOT + ycSyncs.get(j - 1).getDit())
                        .initDeviceCode(emsDevice.getInitDeviceCode()).virtual(VirtualType.REAL.getCode())
                        .deviceCode(emsDevice.getDeviceCode()).productKey(emsDevice.getProductKey()).moduleCode(emsDevice.getModuleCode())
                        .dit(ycSyncs.get(j - 1).getDit()).measureType(MeasureType.yc.getCode())
                        .name("P" + String.format("%02d", i) + "-C" + String.format("%02d", j))//前端编号赋值
                        .build());
            }
            packBatIndex = packBatIndex + emsClusterDetailConfig.getBatteriesNum();
        }
        //查询历史数据
        Map<String,List<OpenApiHisDataVO>> queryList = queryHisDataCommonService.queryYcHisDataByTime(emsDevice.getDeviceCode(),
                hisDataVOList.stream().map(EmsHisDataVO::getDit).collect(Collectors.toList()), time);
        hisDataVOList.stream().forEach(d->{
            List<OpenApiHisDataVO> hisAnalogVOS = queryList.get(d.getPid());
            List<EchartsVO> echartsVOS = Lists.newArrayList();
            if(CollectionUtils.isNotEmpty(hisAnalogVOS)){
                hisAnalogVOS.stream().forEach(f->{
                    echartsVOS.add(EchartsVO.builder().name(String.valueOf(f.getTime())).value(Double.parseDouble(f.getV())).build());
                });
            }
            result.put(d.getName(), echartsVOS);
        });
        //获取单体电压的单位,默认全一致
        IotProductYc iotProductYc = iotProductYcDAO.selectYcByDit(ycSyncList.get(0).getDit(),ycSyncList.get(0).getProductKey());
        BatteryVoltageVO batteryGroupInfoVO = BatteryVoltageVO.builder().voltageList(result)
                .unit(iotProductYc.getUnit()).build();
        return batteryGroupInfoVO;
    }

    /**
     * 获取所有包下的温度图形
     * @param time
     * @param deviceCode
     * @return
     */
    public BatteryTemperatureVO getBatteryTemperatureCurve(Long time, String deviceCode) {
        Map<String, List<EchartsVO>> result = new LinkedHashMap<>();
        EmsDevice emsDevice = this.getBmuMonomerDeviceByClusterDeviceCode(deviceCode);
        //获取当前簇的电池pack分部情况
        EmsClusterConfig emsClusterConfig = emsClusterConfigDAO.getByDeviceCode(deviceCode);
        if(emsClusterConfig == null){
            return BatteryTemperatureVO.builder().build();
        }
        List<EmsClusterDetailConfig> detailConfigList = emsClusterDetailConfigDAO.getListByType(emsClusterConfig.getType());
        if(CollectionUtils.isEmpty(detailConfigList)){
            return BatteryTemperatureVO.builder().build();
        }
        Map<Integer, EmsClusterDetailConfig> detailConfigMap = detailConfigList.stream().collect(Collectors.toMap(EmsClusterDetailConfig::getPack, d -> d, (p1, p2) -> p1));
        Integer tempTotalNum = 0;
        for (EmsClusterDetailConfig config : detailConfigList){
            tempTotalNum = tempTotalNum + config.getTemperNum();
        }
        //获取簇下的单体电压点号,并截取部分数据
        List<ExtIotViceProductYc> ycSyncList = extIotViceProductYcDAO.getBaseMapper().selectByCondition(emsDevice.getProductKey(), emsDevice.getModuleCode(),
                TagType.DTT.getCode());
        if(tempTotalNum > ycSyncList.size()){
            throw new CommonRuntimeException(StatusType.FAIL,"该簇对应的电池簇模型的测温点个数配置有误!");
        }
        ycSyncList = ycSyncList.subList(0, tempTotalNum);
        // 拼接查询点号VO类
        List<EmsHisDataVO> hisDataVOList = Lists.newArrayList();
        //用来指向当前pack的电芯数的最后一个大小
        Integer packBatIndex = 0;
        for (int i = 1; i <= detailConfigMap.size(); i++) {
            EmsClusterDetailConfig emsClusterDetailConfig = detailConfigMap.get(i);
            List<ExtIotViceProductYc> ycSyncs = ycSyncList.subList(packBatIndex, packBatIndex + emsClusterDetailConfig.getTemperNum());
            for (int j = 1; j <= ycSyncs.size(); j++) {
                hisDataVOList.add(EmsHisDataVO.builder()
                        .pid(emsDevice.getInitDeviceCode() + SysConstant.SPOT + ycSyncs.get(j - 1).getDit())
                        .initDeviceCode(emsDevice.getInitDeviceCode()).virtual(VirtualType.REAL.getCode())
                        .deviceCode(emsDevice.getDeviceCode()).productKey(emsDevice.getProductKey()).moduleCode(emsDevice.getModuleCode())
                        .dit(ycSyncs.get(j - 1).getDit()).measureType(MeasureType.yc.getCode())
                        .name(String.format("P%s-C%s",String.format("%02d", i),String.format("%02d", j)))//前端编号赋值
                        .build());
            }
            packBatIndex = packBatIndex + emsClusterDetailConfig.getTemperNum();
        }
        //查询历史数据
        Map<String,List<OpenApiHisDataVO>> queryList = queryHisDataCommonService.queryYcHisDataByTime(emsDevice.getDeviceCode(),
                hisDataVOList.stream().map(EmsHisDataVO::getDit).collect(Collectors.toList()), time);
        hisDataVOList.stream().forEach(d->{
            List<OpenApiHisDataVO> hisAnalogVOS = queryList.get(d.getPid());
            List<EchartsVO> echartsVOS = Lists.newArrayList();
            if(CollectionUtils.isNotEmpty(hisAnalogVOS)){
                hisAnalogVOS.stream().forEach(f->{
                    echartsVOS.add(EchartsVO.builder().name(String.valueOf(f.getTime())).value(Double.parseDouble(f.getV())).build());
                });
            }
            result.put(d.getName(), echartsVOS);
        });
        //获取测温点的单位,默认全一致
        IotProductYc iotProductYc = iotProductYcDAO.selectYcByDit(ycSyncList.get(0).getDit(),ycSyncList.get(0).getProductKey());
        BatteryTemperatureVO batteryTemperatureVO = BatteryTemperatureVO.builder().temperatureList(result)
                .unit(iotProductYc.getUnit()).build();
        return batteryTemperatureVO;
    }

    /**
     * 获取蔟下所有电芯电压表格
     * @param deviceCode: 设备code
     * @return
     */
    public List<BatteryVoltageTableVO> getBatteryVoltageTable(String deviceCode) {
        List<BatteryVoltageTableVO> batteryVoltageTableVOS = Lists.newArrayList();
        EmsDevice emsDevice = this.getBmuMonomerDeviceByClusterDeviceCode(deviceCode);
        //获取当前簇下的单体个数
        EmsClusterConfig emsClusterConfig = emsClusterConfigDAO.getByDeviceCode(deviceCode);
        if(emsClusterConfig == null){
            return Lists.newArrayList();
        }
        List<EmsClusterDetailConfig> detailConfigList = emsClusterDetailConfigDAO.getListByType(emsClusterConfig.getType());
        if(CollectionUtils.isEmpty(detailConfigList)){
            return Lists.newArrayList();
        }
        Map<Integer, EmsClusterDetailConfig> detailConfigMap = detailConfigList.stream().collect(Collectors.toMap(EmsClusterDetailConfig::getPack, d -> d, (p1, p2) -> p1));
        Integer batteriesTotalNum = 0;
        //单个pack的最大电芯数
        Integer maxPackBatNum = 0;
        for (EmsClusterDetailConfig config : detailConfigList) {
            batteriesTotalNum = batteriesTotalNum + config.getBatteriesNum();
            maxPackBatNum = Math.max(maxPackBatNum, config.getBatteriesNum());
        }
        //获取簇下的单体电压点号,截取部分数据
        List<ExtIotViceProductYc> ycSyncList = extIotViceProductYcDAO.getBaseMapper().selectByCondition(emsDevice.getProductKey(), emsDevice.getModuleCode(),
                TagType.DTU.getCode());
        if(batteriesTotalNum > ycSyncList.size()){
            throw new CommonRuntimeException(StatusType.FAIL,"该簇对应的电池簇模型的电压个数配置有误!");
        }
        ycSyncList = ycSyncList.subList(0, batteriesTotalNum);
        // 把电池组排列，然后，获取所有的电池信息
        Map<Integer, List<String>> voltageTableNumMap = Maps.newHashMap();
        //封装需要查询的实时数据结果集
        List<EmsDeviceLocationVO> locationVOList = Lists.newArrayList();
        Map<String, Double> valueMap = Maps.newHashMap();
        List<String> measureIds = Lists.newArrayList();
        //用来指向当前pack的电芯数的最后一个大小
        Integer packBatIndex = 0;
        for (int i = 1; i <= detailConfigMap.size(); i++) {
            EmsClusterDetailConfig emsClusterDetailConfig = detailConfigMap.get(i);
            List<ExtIotViceProductYc> ycSyncs = ycSyncList.subList(packBatIndex, packBatIndex + emsClusterDetailConfig.getBatteriesNum());
            for (int j = 1; j <= ycSyncs.size(); j++) {
                measureIds.add(emsDevice.getInitDeviceCode() + SysConstant.SPOT + ycSyncs.get(j - 1).getDit());
                locationVOList.add(EmsDeviceLocationVO.builder()
                        .pid(emsDevice.getInitDeviceCode() + SysConstant.SPOT + ycSyncs.get(j - 1).getDit())
                        .initDeviceCode(emsDevice.getInitDeviceCode()).virtual(VirtualType.REAL.getCode())
                        .deviceCode(emsDevice.getDeviceCode()).productKey(emsDevice.getProductKey()).moduleCode(emsDevice.getModuleCode())
                        .dit(ycSyncs.get(j - 1).getDit()).measureType(MeasureType.yc.getCode())
                        .build());
            }
            voltageTableNumMap.put(i, Lists.newArrayList(measureIds));
            measureIds.clear();
            packBatIndex = packBatIndex + emsClusterDetailConfig.getBatteriesNum();
        }
        //调用查询实时数据接口
        List<FlashDataVO> flashVOS = queryFlashDataCommonService.getFlashData(JacksonUtil.convertToList(locationVOList, QueryDataVO.class));
        if (CollectionUtils.isNotEmpty(flashVOS)) {
            flashVOS.stream().forEach(d -> {
                valueMap.put(d.getPid(), Double.parseDouble(d.getVal()));
            });
        }
        for (Integer packNum : voltageTableNumMap.keySet()) {
            List<EchartsVO> tableValueVO = Lists.newArrayList();
            for (String measureId : voltageTableNumMap.get(packNum)) {
                tableValueVO.add(EchartsVO.builder().name(measureId)
                        .value(valueMap.get(measureId)).build());
            }
            if (tableValueVO.size() < maxPackBatNum) {
                this.fakeDataWithEchartsVO(tableValueVO, maxPackBatNum - tableValueVO.size());
            }
            batteryVoltageTableVOS.add(BatteryVoltageTableVO.builder().pack(packNum).batteryVoltageVOS(tableValueVO).build());
        }
        batteryVoltageTableVOS.stream().sorted(Comparator.comparing(BatteryVoltageTableVO::getPack));
        return batteryVoltageTableVOS;
    }

    /**
     * 获取所有包下的温度表格
     * @param deviceCode: 设备code
     */
    public List<BatteryTemperatureTableVO> getBatteryTemperatureTable(String deviceCode) {
        List<BatteryTemperatureTableVO> batteryTemperatureTableVOS = Lists.newArrayList();
        EmsDevice emsDevice = this.getBmuMonomerDeviceByClusterDeviceCode(deviceCode);
        //获取当前簇下的单体个数
        EmsClusterConfig emsClusterConfig = emsClusterConfigDAO.getByDeviceCode(deviceCode);
        if(emsClusterConfig == null){
            return Lists.newArrayList();
        }
        List<EmsClusterDetailConfig> detailConfigList = emsClusterDetailConfigDAO.getListByType(emsClusterConfig.getType());
        if(CollectionUtils.isEmpty(detailConfigList)){
            return Lists.newArrayList();
        }
        Map<Integer, EmsClusterDetailConfig> detailConfigMap = detailConfigList.stream().collect(Collectors.toMap(EmsClusterDetailConfig::getPack, d -> d, (p1, p2) -> p1));
        Integer tempTotalNum = 0;
        //单个pack的最大测温点数
        Integer maxPackTempNum = 0;
        for (EmsClusterDetailConfig config : detailConfigList) {
            tempTotalNum = tempTotalNum + config.getTemperNum();
            maxPackTempNum = Math.max(maxPackTempNum, config.getTemperNum());
        }
        //获取簇下的单体电压点号,截取部分数据
        List<ExtIotViceProductYc> ycSyncList = extIotViceProductYcDAO.getBaseMapper().selectByCondition(emsDevice.getProductKey(), emsDevice.getModuleCode(),
                TagType.DTT.getCode());
        if(tempTotalNum > ycSyncList.size()){
            throw new CommonRuntimeException(StatusType.FAIL,"该簇对应的电池簇模型的测温点个数配置有误!");
        }
        ycSyncList = ycSyncList.subList(0, tempTotalNum);
        // 把测温点排列，然后，获取所有的温度信息
        Map<Integer, List<String>> temperatureTableNumMap = Maps.newHashMap();
        //封装需要查询的实时数据结果集
        List<EmsDeviceLocationVO> locationVOList = Lists.newArrayList();
        Map<String, Double> valueMap = Maps.newHashMap();
        List<String> measureIds = Lists.newArrayList();
        //用来指向当前pack的电芯数的最后一个大小
        Integer packBatIndex = 0;
        for (int i = 1; i <= detailConfigMap.size(); i++) {
            EmsClusterDetailConfig emsClusterDetailConfig = detailConfigMap.get(i);
            List<ExtIotViceProductYc> ycSyncs = ycSyncList.subList(packBatIndex, packBatIndex + emsClusterDetailConfig.getTemperNum());
            for (int j = 1; j <= ycSyncs.size(); j++) {
                measureIds.add(emsDevice.getInitDeviceCode() + SysConstant.SPOT + ycSyncs.get(j - 1).getDit());
                locationVOList.add(EmsDeviceLocationVO.builder()
                        .pid(emsDevice.getInitDeviceCode() + SysConstant.SPOT + ycSyncs.get(j - 1).getDit())
                        .initDeviceCode(emsDevice.getInitDeviceCode()).virtual(VirtualType.REAL.getCode())
                        .deviceCode(emsDevice.getDeviceCode()).productKey(emsDevice.getProductKey()).moduleCode(emsDevice.getModuleCode())
                        .dit(ycSyncs.get(j - 1).getDit()).measureType(MeasureType.yc.getCode())
                        .build());
            }
            temperatureTableNumMap.put(i, Lists.newArrayList(measureIds));
            measureIds.clear();
            packBatIndex = packBatIndex + emsClusterDetailConfig.getTemperNum();
        }
        //调用查询实时数据接口
        List<FlashDataVO> flashVOS = queryFlashDataCommonService.getFlashData(JacksonUtil.convertToList(locationVOList, QueryDataVO.class));
        if (CollectionUtils.isNotEmpty(flashVOS)) {
            flashVOS.stream().forEach(d -> {
                valueMap.put(d.getPid(), Double.parseDouble(d.getVal()));
            });
        }
        for (Integer packNum : temperatureTableNumMap.keySet()) {
            List<EchartsVO> tableValueVO = Lists.newArrayList();
            for (String measureId : temperatureTableNumMap.get(packNum)) {
                tableValueVO.add(EchartsVO.builder().name(measureId)
                        .value(valueMap.get(measureId)).build());
            }
            if (tableValueVO.size() < maxPackTempNum) {
                this.fakeDataWithEchartsVO(tableValueVO, maxPackTempNum - tableValueVO.size());
            }
            batteryTemperatureTableVOS.add(BatteryTemperatureTableVO.builder().pack(packNum).batteryTemperatureVOS(tableValueVO).build());
        }
        batteryTemperatureTableVOS.stream().sorted(Comparator.comparing(BatteryTemperatureTableVO::getPack));
        return batteryTemperatureTableVOS;
    }

    /**
     * 获取某个簇设备对应的单体信息设备
     * 一种点号在自身这个设备下，一种点号在该簇设备下一级(簇单体设备)下
     * @return
     */
    private EmsDevice getBmuMonomerDeviceByClusterDeviceCode(String deviceCode){
        EmsDevice emsDevice = emsDeviceDAO.selectByDeviceCode(deviceCode);
        Assert.notNull(emsDevice,"设备不存在！");
        Assert.isTrue(Objects.equals(emsDevice.getDeviceType(), DeviceType.CLUSTER.getCode()),"只能为簇设备！");
        //判断当前簇设备是否还有簇单体设备，如果有单体电压点号应从该设备对应的产品获取
        List<EmsDevice> bmuMonomerList = emsDeviceDAO.getChildDeviceByCondition(deviceCode,DeviceType.BMU_MONOMER.getCode());
        if(!CollectionUtils.isEmpty(bmuMonomerList)){
            emsDevice = bmuMonomerList.get(0);
        }
        return emsDevice;
    }

    /**
     * 补全表格中每一行的数据
     *
     * @param tableValueVO
     * @param fakeNum
     */
    private void fakeDataWithEchartsVO(List<EchartsVO> tableValueVO, Integer fakeNum) {
        for (int i = 0; i < fakeNum; i++) {
            tableValueVO.add(EchartsVO.builder().build());
        }
    }
}
